#pragma once

#include "LeDocumentObject_global.h"

#include <QObject>

class QIODevice;
class QXmlStreamReader;

class TestDocumentStreamReader;

namespace LDO
{

    class Document;
    class IDocumentObject;

    class LDO_EXPORT DocumentStreamReader : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(bool strictMode READ strictMode WRITE setStrictMode NOTIFY strictModeChanged)
        Q_PROPERTY(bool debugEnabled READ debugEnabled WRITE setDebugEnabled NOTIFY debugEnabledChanged)

        friend class ::TestDocumentStreamReader;

    public:
        explicit DocumentStreamReader(QObject *parent = nullptr);

        void setDevice(QIODevice *device);
        QIODevice *device() const;

        bool readDocument(Document *document);
        QString errorString() const;

        bool strictMode() const;
        bool debugEnabled() const;

    public slots:
        void setStrictMode(bool strict);
        void setDebugEnabled(bool enabled);

    signals:
        void strictModeChanged(bool strict);
        void debugEnabledChanged(bool enabled);

    private:
        IDocumentObject *readObject(const QMetaObject &metaObject);
        QVariant readPropertyValue(const QMetaProperty &metaProperty, const QString &wantedTypeName = QString());

        QVariant readIntValue();
        QVariant readDoubleValue();
        QVariant readBoolValue();
        QVariant readStringValue();
        QVariant readStringListValue();
        QVariant readPointValue();
        QVariant readSizeValue();
        QVariant readEnumValue(int typeId, const QMetaEnum &metaEnum);
        QVariant readFlagValue(int typeId, const QMetaEnum &metaEnum);

        QVariant readListOfIntValue();
        QVariant readListOfDoubleValue();
        QVariant readListOfBoolValue();
        QVariant readListOfStringValue();
        QVariant readListOfPointValue();
        QVariant readListOfSizeValue();
        QVariant readListOfStringListValue();
        QVariant readListOfObjectStarValue(const QString &classPointerTypeName);
        QVariant readListOf(const QString &typeName);

        QVariant readObjectStarValue(const QString &typeName);

        // TBD: Geometry, object link

        // TODO: pen, brush, color,
        // date, time, date-time, font, uuid
        // transform, Dir, and File path, URL

        bool readNextStartElement();
        QString readElementText();
        bool isNamed(const QString &name);
        bool hasAttribute(const QString &name);
        QString attributeValue(const QString &name);
        void skipCurrentElement();
        void raiseWarning(const QString &message);
        void raiseError(const QString &message);
        bool isDerivedFrom(const QString &pointerTypeName, const QString &superPointerTypeName);
        Document *m_document = nullptr;
        QXmlStreamReader *m_reader = nullptr;
        bool m_strictMode = true;
        bool m_debugEnabled = false;
    };

}
